home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / NextAnswers / UniqueKey_sybase / UniqueKey.m < prev    next >
Text File  |  1994-06-14  |  7KB  |  210 lines

  1. #import <appkit/appkit.h>
  2. #import "UniqueKey.h"
  3.  
  4.  
  5. static BOOL  _Debug = YES;
  6. static id    _connectionDictionary = nil;
  7.  
  8.  
  9. @implementation UniqueKey
  10.  
  11. /******************************************************************************
  12. * Allow the programmer to specify login information for our separate UniqueKey
  13. * channel.  If no information is supplied, we display our own login panel.
  14. ******************************************************************************/
  15. + setConnectionDictionary:(NSDictionary *)connectionDictionary
  16. {
  17.     if(_connectionDictionary) [_connectionDictionary autorelease];
  18.     _connectionDictionary = [connectionDictionary retain];
  19.     return self;
  20. }
  21. + connectionDictionary
  22. {
  23.     return [[_connectionDictionary retain] autorelease];
  24. }
  25.  
  26.  
  27. /******************************************************************************
  28. * The UniqueKey objects share a database channel that is sure
  29. * to be free to allow immediate reservation of a block of keys.
  30. ******************************************************************************/
  31. - initSharedChannel
  32. {
  33.     NSString            *modelName = @"UniqueKey";
  34.     NSString            *path;
  35.     NSString            *_entityName = @"UniqueKey";
  36.     EOModel            *eoModel;
  37.     EOAdaptor            *eoAdaptor;
  38.     EODatabase            *db;
  39.     static EODatabaseContext    *_sharedContext;
  40.     static EODatabaseChannel    *_sharedChannel;
  41.     static EOEntity        *_sharedEntity;
  42.     static BOOL            initFlag = NO;
  43.     
  44.     if(!initFlag) {
  45.     path = [EOModel findPathForModelNamed:modelName];
  46.         if(!path) {
  47.             NXRunAlertPanel([NXApp appName],
  48.             "UniqueKey is unable to find %s",NULL,NULL,NULL,[modelName cString]);
  49.         return nil;
  50.     }
  51.     
  52.     eoModel=[[EOModel alloc] initWithContentsOfFile:path];
  53.     if(!eoModel) {
  54.             NXRunAlertPanel([NXApp appName],
  55.             "UniqueKey is unable to open %s",NULL,NULL,NULL,[path cString]);
  56.         return nil;
  57.         }
  58.      
  59.         eoAdaptor=[[EOAdaptor adaptorWithModel:eoModel] retain];
  60.        if(!eoAdaptor) {
  61.             NXRunAlertPanel([NXApp appName],
  62.             "UniqueKey is unable to create adaptorWithModel:",NULL,NULL,NULL);
  63.         return nil;
  64.         }
  65.      
  66.     if([UniqueKey connectionDictionary]!=nil)
  67.         [eoAdaptor setConnectionDictionary:[UniqueKey connectionDictionary]];
  68.     if(![eoAdaptor hasValidConnectionDictionary])
  69.         [eoAdaptor runLoginPanelAndValidateConnectionDictionary];
  70.  
  71.        db=[[EODatabase alloc] initWithAdaptor:eoAdaptor];
  72.        if(!db) {
  73.             NXRunAlertPanel([NXApp appName],
  74.             "UniqueKey is unable to initWithAdaptor:",NULL,NULL,NULL);
  75.         return nil;
  76.         }
  77.     
  78.         _sharedContext=[[EODatabaseContext alloc] initWithDatabase:db];
  79.         if(!_sharedContext) {
  80.             NXRunAlertPanel([NXApp appName],
  81.             "UniqueKey is unable to initWithDatabase:",NULL,NULL,NULL);
  82.         return nil;
  83.         }
  84.     
  85.         _sharedChannel=[[EODatabaseChannel alloc] initWithDatabaseContext:_sharedContext];
  86.         if(!_sharedChannel) {
  87.             NXRunAlertPanel([NXApp appName],
  88.             "UniqueKey is unable to initWithDatabaseContext:",NULL,NULL,NULL);
  89.         return nil;
  90.        }
  91.     
  92.         _sharedEntity=[[eoModel entityNamed:_entityName] retain];
  93.         if(!_sharedEntity) {
  94.             NXRunAlertPanel([NXApp appName],
  95.             "UniqueKey is unable to find entityNamed:%s",NULL,NULL,NULL,[_entityName cString]);
  96.         return nil;
  97.         }
  98.  
  99.     [[_sharedChannel adaptorChannel] openChannel];
  100.     if(_Debug) [[_sharedChannel adaptorChannel] setDelegate:self];
  101.  
  102.     initFlag=TRUE;
  103.     }
  104.     
  105.     dbContext        = [_sharedContext retain];
  106.     dbChannel        = [_sharedChannel retain];
  107.     uniqueKeyEntity  = [_sharedEntity retain];
  108.     return self;
  109. }
  110.  
  111.  
  112. /******************************************************************************
  113. * Init a UniqueKey object to reserve integer keys in blocks of <count> keys.  Hold
  114. * off reserving any keys until the first call to nextKey.  Each call to nextKey
  115. * returns a unique integer key.  The first call reserves a block of <count> keys.
  116. * When the block has been used, a new block is reserved.
  117. *
  118. * UniqueKey uses a separate table to hold the external entity name and current
  119. * max reserved integer key.  The UniqueKey objects share a database channel that
  120. * is sure to be free to allow immediate reservation of a block of keys.
  121. ******************************************************************************/
  122. - initWithEntity:(EOEntity*)entity count:(unsigned int)count
  123. {
  124.     NSString    *qualifierString;
  125.     EOQualifier    *tableNameQualifier;
  126.     NSNumber    *max;
  127.  
  128.     keyCount   = count;
  129.     nextKey    = 0;
  130.     maxKey     = 0;
  131.     
  132.     if(!entity || ![self initSharedChannel]) return nil;
  133.  
  134.     // Construct the qualifier for our name
  135.     qualifierString = [NSString stringWithFormat:@"EntityName = '%@'",[entity externalName]];
  136.     
  137.     tableNameQualifier = [[[EOQualifier allocWithZone:[self zone]]
  138.         initWithEntity:uniqueKeyEntity qualifierFormat:qualifierString] autorelease];
  139.  
  140.     // Select the object and check for the presence of our name and "MaxKey"
  141.     [dbContext beginTransaction];
  142.     [dbChannel selectObjectsDescribedByQualifier:tableNameQualifier fetchOrder:nil];
  143.     tableMax=[[dbChannel fetchWithZone:[dbChannel zone]] retain];
  144.     [dbChannel cancelFetch];
  145.     [dbContext commitTransaction];
  146.     
  147.     // Was there an entry for our table name?
  148.     if(!tableMax) {
  149.         NSLog(@"Unique key was unable to fetch EntityName = %@",[entity externalName]);
  150.     return nil;
  151.     }
  152.     
  153.     // Then there should be a value for "MaxKey" for our table
  154.     max=[tableMax objectForKey:@"MaxKey"];
  155.     if(!max) {
  156.     NSLog(@"Unique key method nextKey could not fine MaxKey");
  157.     return nil;
  158.     }
  159.     return self;
  160. }
  161.  
  162.  
  163. /******************************************************************************
  164. * Hand out the next unique key from our reserved block.  If the block is exhausted,
  165. * increment the max_id (high-water mark) and attempt to updateObject:.  This
  166. * writes the new max_id back to the table.  Under optimistic locking (the default)
  167. * the update will fail if another client has bumped up the max_id since our last use.
  168. * In that case, we need to refetchObject: and try again.
  169. ******************************************************************************/
  170. - (int) nextKey
  171. {
  172.     NSNumber    *max;
  173.  
  174.     // Hand out our next reserved key.  If we are out of keys, fall through to
  175.     // reserve another block of keyCount keys.
  176.     if(++nextKey<=maxKey) return nextKey;
  177.     
  178.     // Attempt to bump up the count by keyCount.  Fail on optomistic lock if someone
  179.     // else reserved a chunck since our original select (or our last update).
  180.     [dbContext beginTransaction];
  181.     while(1) {
  182.     max    = [tableMax objectForKey:@"MaxKey"];
  183.     maxKey = [max intValue]+keyCount;
  184.     [tableMax setObject:[NSNumber numberWithInt:maxKey] forKey:@"MaxKey"];
  185.         if([dbChannel updateObject:tableMax]) break;
  186.  
  187.     [dbContext rollbackTransaction];
  188.     [dbContext beginTransaction];
  189.     [dbChannel refetchObject:tableMax];
  190.     }
  191.     [dbContext commitTransaction];
  192.     
  193.     nextKey=maxKey-keyCount+1;
  194.     return nextKey;
  195. }
  196.  
  197.  
  198. /******************************************************************************
  199. * Echo SQL when debug is enabled.
  200. ******************************************************************************/
  201. - (EODelegateResponse)adaptorChannel:channel
  202.     willEvaluateExpression:(NSMutableString *)expression
  203. {
  204.     NSLog(expression);
  205.     return EODelegateApproves;
  206. }
  207.  
  208.  
  209. @end
  210.